<script setup>
import { ref, onMounted, inject } from "vue";
import { ElMessage } from "element-plus";
import { Rank, Plus, Edit, Delete } from "@element-plus/icons-vue";
import { BREADCRUMBS, APP_CODE } from "@/plugins/global";
import { cloneDeep } from "lodash";

const axios = inject("axios");

// ---- 初始化。
onMounted(() => {
  BREADCRUMBS.splice(0, BREADCRUMBS.length,
    { "label": "权限树", "path": "/home/authority" }
  );
  authorityTreeGet();
});

// ---- 权限树获取：获取权限树的数据。
const authorityTree = ref([]), authorityTreeProps = {
  "label": "name",
  "children": "children",
}
const authorityTreeGet = () => {
  axios.get("/api/cms-web/authority/get/tree").then(response => {
    if (response.data.success) {
      if (response.data.data) {
        authorityTree.value = response.data.data.children;
      }
    } else {
      ElMessage.error(response.data.message);
    }
  });
}

// ---- 权限节点展开：记录被展开的权限节点。
const authorityExpandedNodes = ref(new Set());
const authorityNodeExpand = (data, node, component) => {
  authorityExpandedNodes.value.add(data.authorityCode);
}

// ---- 权限节点闭合：剔除被关闭的权限节点。
const authorityNodeCollapse = (data, node, component) => {
  authorityExpandedNodes.value.delete(data.authorityCode);
}

// ---- 权限树排序开始：进入排序模式，并深拷贝当前权限节点的开合数据用于重置/退出时还原。
const authorityTreeSortFlag = ref(false), authorityTreeCopy = ref(null), authorityExpandedNodesCopy = ref(null);
const authorityTreeSortStart = () => {
  authorityTreeSortFlag.value = true;
  authorityTreeCopy.value = cloneDeep(authorityTree.value);
  authorityExpandedNodesCopy.value = cloneDeep(authorityExpandedNodes.value);
}

// ---- 权限树排序重置：还原权限树为刚进入排序模式的状态。
const authorityTreeSortReset = () => {
  authorityTree.value = cloneDeep(authorityTreeCopy.value);
  authorityExpandedNodes.value = cloneDeep(authorityExpandedNodesCopy.value);
}

// ---- 权限树排序取消：还原权限树为刚进入排序模式的状态并退出排序模式。
const authorityTreeSortCancel = () => {
  authorityTreeSortReset();
  authorityTreeCopy.value = null;
  authorityExpandedNodesCopy.value = new Set();
  authorityTreeSortFlag.value = false;
}

// ---- 权限树排序判断：确保权限节点只能在所属父级权限下拖拽&排序。
const authorityTreeSortJudge = (draggingNode, dropNode, type) => {
  // ---- 如果目标权限节点不存在，说明将之赋值为根权限节点。这种情况下必然是拖拽至下级。
  const dropNodeCode = dropNode ? dropNode.data.authorityCode : APP_CODE;
  const draggingNodeCode = draggingNode.data.authorityCode;
  // ---- 获取拖拽权限节点的父级权限节点。
  let lastIndex = draggingNodeCode.lastIndexOf("/");
  const parentNodeCode1 = draggingNodeCode.substring(0, lastIndex);
  if (type === "inner") {
    // ---- 如果放置于目标权限节点下级，那么目标权限节点必须是拖拽权限节点的父级权限节点。
    return parentNodeCode1 === dropNodeCode;
  } else {
    // ---- 如果放置于目标权限节点同级，那么目标节点与拖拽权限节点的父级权限节点必须相同。 
    lastIndex = dropNodeCode.lastIndexOf("/");
    const parentNodeCode2 = dropNodeCode.substring(0, lastIndex);
    return parentNodeCode1 === parentNodeCode2;
  }
};

// ---- 权限树排序警告：在权限节点被拖拽至所属父级权限节点外部时抛出警告。
const authorityTreeSortWarn = (draggingNode, dropNode, type) => {
  if (!authorityTreeSortJudge(draggingNode, dropNode, type)) {
    ElMessage.error("排序只允许在同父级下进行！");
  }
};

// ---- 权限树排序确认：正式排序权限树。
const authorityTreeSortConfirm = () => {
  const authority = { "authorityCode": APP_CODE, "children": authorityTree.value };
  axios.post("/api/cms-web/authority/sort/tree", authority).then(response => {
    if (response.data.success) {
      ElMessage.success("排序成功！");
      authorityTree.value = response.data.data.children;
      authorityTreeCopy.value = null;
      authorityExpandedNodesCopy.value = new Set();
      authorityTreeSortFlag.value = false;
    } else {
      ElMessage.error(response.data.message);
    }
  });
}

// ---- 权限插入/更新准备。
let authorityUpsertBase = null, authorityUpsertType = null;
const authorityUpsertFormRef = ref(null), authorityUpsertFlag = ref(false);
const authorityUpsert = ref({
  "authorityCodePrefix": null,
  "authorityCode": null,
  "name": null,
  "sort": null,
  "apiCodes": []
});
const authorityUpsertPrepare = (type, base) => {
  // ---- 重置插入表单。
  if (authorityUpsertFormRef.value) {
    authorityUpsertFormRef.value.resetFields();
  }
  authorityUpsertBase = base;
  const authorityCodeBase = authorityUpsertBase.authorityCode;
  authorityUpsertType = type;
  if (authorityUpsertType === "insert_brother") {
    // ---- 插入兄弟权限节点准备。
    const lastIndex = authorityCodeBase.lastIndexOf("/");
    authorityUpsert.value.authorityCodePrefix = authorityCodeBase.substring(0, lastIndex) + "/";
    authorityUpsert.value.authorityCode = null;
    authorityUpsert.value.name = null;
    authorityUpsert.value.sort = base.sort;
    authorityUpsert.value.apiCodes = [];
  } else if (authorityUpsertType === "insert_children") {
    // ---- 插入孩子权限节点准备。
    authorityUpsert.value.authorityCodePrefix = authorityCodeBase + "/";
    authorityUpsert.value.authorityCode = null;
    authorityUpsert.value.name = null;
    authorityUpsert.value.sort = base.children.length;
    authorityUpsert.value.apiCodes = [];
  } else if (authorityUpsertType === "update") {
    // ---- 更新权限节点准备。
    authorityUpsert.value.authorityCodePrefix = null;
    authorityUpsert.value.authorityCode = authorityCodeBase;
    authorityUpsert.value.name = base.name;
    authorityUpsert.value.sort = base.sort;
    authorityUpsert.value.apiCodes = base.apiCodes;
  } else {
    // ---- 插入首个权限节点准备。
    authorityUpsert.value.authorityCodePrefix = authorityCodeBase + "/";
    authorityUpsert.value.authorityCode = null;
    authorityUpsert.value.name = null;
    authorityUpsert.value.sort = 0;
    authorityUpsert.value.apiCodes = [];
  }
  authorityUpsertFlag.value = true;
}

// ---- 权限插入/更新确认。
const authorityTreeRef = ref(null), authorityUpsertFormRules = ref({
  "authorityCode": [{ required: true, message: "请输入编码！", trigger: "blur" }],
  "name": [{ required: true, message: "请输入名称！", trigger: "blur" }]
});
const authorityUpsertConfirm = () => {
  authorityUpsertFormRef.value.validate((valid) => {
    if (valid) {
      if (authorityUpsertType === "insert_brother") {
        // ---- 插入兄弟权限节点。
        authorityUpsert.value.authorityCode = authorityUpsert.value.authorityCodePrefix + authorityUpsert.value.authorityCode;
        axios.post("/api/cms-web/authority/insert", authorityUpsert.value).then(response => {
          if (response.data.success) {
            ElMessage.success("插入成功！");
            authorityTreeRef.value.insertAfter(authorityUpsert.value, authorityUpsertBase.authorityCode);
            authorityUpsertFlag.value = false;
          } else {
            ElMessage.error(response.data.message);
          }
        });
      } else if (authorityUpsertType === "insert_children") {
        // ---- 插入孩子权限节点。
        authorityUpsert.value.authorityCode = authorityUpsert.value.authorityCodePrefix + authorityUpsert.value.authorityCode;
        axios.post("/api/cms-web/authority/insert", authorityUpsert.value).then(response => {
          if (response.data.success) {
            ElMessage.success("插入成功！");
            authorityTreeRef.value.append(authorityUpsert.value, authorityUpsertBase.authorityCode);
            authorityUpsertFlag.value = false;
          } else {
            ElMessage.error(response.data.message);
          }
        });
      } else if (authorityUpsertType === "update") {
        // ---- 更新权限节点。
        axios.post("/api/cms-web/authority/update", authorityUpsert.value).then(response => {
          if (response.data.success) {
            ElMessage.success("更新成功！");
            const authorityNode = authorityTreeRef.value.getNode(authorityUpsert.value.authorityCode);
            authorityNode.data.name = authorityUpsert.value.name;
            authorityUpsertFlag.value = false;
          } else {
            ElMessage.error(response.data.message);
          }
        });

      } else {
        // ---- 插入首个权限节点准备。
        authorityUpsert.value.authorityCode = authorityUpsert.value.authorityCodePrefix + authorityUpsert.value.authorityCode;
        axios.post("/api/cms-web/authority/insert", authorityUpsert.value).then(response => {
          if (response.data.success) {
            ElMessage.success("插入成功！");
            authorityTreeGet();
            authorityUpsertFlag.value = false;
          } else {
            ElMessage.error(response.data.message);
          }
        });
      }
    }
  });
}

// ---- 接口插入：新增一个接口输入框。
const apiInsert = () => {
  authorityUpsert.value.apiCodes.push("");
}

// ---- 接口删除：删除一个接口。
const apiDelete = (index) => {
  authorityUpsert.value.apiCodes.splice(index, 1);
}

// ---- 权限删除准备。
const authorityDeleteFlag = ref(false), authorityDelete = ref(null);
const authorityDeletePrepare = (authority) => {
  authorityDeleteFlag.value = true;
  authorityDelete.value = authority;
}

// ---- 权限删除确认。
const authorityDeleteConfirm = () => {
  axios.delete(`/api/cms-web/authority/delete/tree?rootAuthorityCode=${authorityDelete.value.authorityCode}`).then(response => {
    if (response.data.success) {
      ElMessage.success("删除成功！");
      // ---- 从权限树中删除指定权限。
      authorityTreeRef.value.remove(authorityDelete.value);
      authorityDeleteFlag.value = false;
    } else {
      ElMessage.error(response.data.message);
    }
  });
}
</script>

<template>
  <div class="authority-tree-page-div-class">
    <!-- 权限树域 -->
    <el-button type="primary" @click="authorityUpsertPrepare('insert_first', { 'authorityCode': APP_CODE })"
      style="width: 100%;" v-if="!authorityTree || authorityTree.length === 0">插入权限</el-button>
    <div class="authority-tree-div-class" v-if="authorityTree && authorityTree.length !== 0">
      <el-tree ref="authorityTreeRef" node-key="authorityCode" :data="authorityTree" :draggable="authorityTreeSortFlag"
        :props="authorityTreeProps" :expand-on-click-node="false" :allow-drop="authorityTreeSortJudge"
        :default-expanded-keys="Array.from(authorityExpandedNodes)" @node-drag-end="authorityTreeSortWarn"
        @node-expand="authorityNodeExpand" @node-collapse="authorityNodeCollapse" style="width: 100%;">
        <template #default="{ node, data }">
          <div class="authority-tree-node-class">
            <span>[{{ data.authorityCode }}] - {{ data.name }}</span>
            <div v-if="authorityTreeSortFlag === false">
              <el-tooltip content="插入兄弟" placement="left" effect="light">
                <el-button :icon="Rank" circle size="small" @click="authorityUpsertPrepare('insert_brother', data)" />
              </el-tooltip>
              <el-tooltip content="插入孩子" placement="right" effect="light">
                <el-button :icon="Plus" circle size="small" @click="authorityUpsertPrepare('insert_children', data)" />
              </el-tooltip>
              <el-button :icon="Edit" circle size="small" type="primary"
                @click="authorityUpsertPrepare('update', data)" />
              <el-button :icon="Delete" circle size="small" type="danger" @click="authorityDeletePrepare(data)" />
            </div>
          </div>
        </template>
      </el-tree>
    </div>
    <div class="authority-tree-sort-div-class" v-if="authorityTree && authorityTree.length !== 0">
      <el-button @click="authorityTreeSortStart()" v-if="authorityTreeSortFlag === false">排序</el-button>
      <div v-else>
        <el-button @click="authorityTreeSortCancel()">取消</el-button>
        <el-button @click="authorityTreeSortReset()">重置</el-button>
        <el-button type="primary" @click="authorityTreeSortConfirm()">确定</el-button>
      </div>
    </div>
  </div>
  <!-- 权限插入/更新域 -->
  <el-dialog v-model="authorityUpsertFlag" width="30%" style="padding: 30px 20px 20px 20px;">
    <el-form ref="authorityUpsertFormRef" :model="authorityUpsert" :rules="authorityUpsertFormRules"
      require-asterisk-position="right" class="authority-upsert-form-class">
      <el-form-item label="编码" prop="authorityCode" style="width: 100%" v-if="authorityUpsertType !== 'update'">
        <el-input v-model="authorityUpsert.authorityCode" style="width: 100%">
          <template #prepend>{{ authorityUpsert.authorityCodePrefix }}</template>
        </el-input>
      </el-form-item>
      <el-form-item label="编码" prop="authorityCode" style="width: 100%" v-else>
        <el-input v-model="authorityUpsert.authorityCode" disabled style="width: 100%" />
      </el-form-item>
      <el-form-item label="名称" prop="name" style="width: 100%">
        <el-input v-model="authorityUpsert.name" autocomplete="off" style="width: 100%" />
      </el-form-item>
      <el-form-item label="接口集" prop="apiCodes" style="width: 100%">
        <el-button @click="apiInsert()" style="width: 100%">+</el-button>
        <div v-for="(item, index) in authorityUpsert.apiCodes" :key="index"
          style="display: flex; justify-content: space-between; align-items: flex-end; width: 100%; gap: 3px;">
          <el-input v-model="authorityUpsert.apiCodes[index]" size="small" style="width: 90%; padding-top: 3px;" />
          <el-button type="danger" :icon="Delete" size="small" @click="apiDelete(index)" style="width: 10%;" />
        </div>
      </el-form-item>
      <div style="display: flex; flex-direction: row; justify-content: center; width: 100%; padding-top: 5px;">
        <el-button @click="authorityUpsertFlag = false">取消</el-button>
        <el-button type="primary" @click="authorityUpsertConfirm()">确定</el-button>
      </div>
    </el-form>
  </el-dialog>
  <!-- 权限删除域 -->
  <el-dialog header="确认删除" v-model="authorityDeleteFlag" width="30%" style="padding: 30px 20px 20px 20px;">
    <div style="padding-bottom: 10px">您确定要删除权限[{{ authorityDelete.name }}]吗？这将导致持有该权限的员工无法执行相应操作！</div>
    <template #footer>
      <span>
        <el-button @click="authorityDeleteFlag = false">取消</el-button>
        <el-button type="primary" @click="authorityDeleteConfirm()">确定</el-button>
      </span>
    </template>
  </el-dialog>
</template>

<style scoped>
.authority-tree-page-div-class {
  display: flex;
  flex-direction: column;
  width: 100%;
  height: 100%;
  padding: 20px 20px 20px 20px;
}

.authority-tree-div-class {
  flex: 1;
  display: flex;
  flex-direction: column;
  justify-content: flex-start;
  align-items: flex-start;
  width: 100%;
  height: 94.5%;
  /* ---- 溢出：滚动，但隐藏滚动条，不同的浏览器隐藏滚动条有不同的配置 */
  overflow: auto;

  /* ---- Chrome/Safari */
  &::-webkit-scrollbar {
    display: none;
  }

  /* ---- IE/Edge */
  -ms-overflow-style: none;
  /* ---- Firefox */
  scrollbar-width: none;
}

.authority-tree-node-class {
  display: flex;
  flex-direction: row;
  justify-content: space-between;
  align-items: flex-end;
  width: 100%;
}

.authority-upsert-form-class {
  display: flex;
  flex-direction: column;
  justify-content: flex-start;
  align-items: center;
  width: 100%;
}

.authority-tree-sort-div-class {
  display: flex;
  flex-direction: row;
  justify-content: flex-end;
  align-items: flex-end;
  width: 100%;
  height: 5.5%;
  border-top: 1px solid rgb(171, 164, 164);
}
</style>
